#ifndef _GAME_MEMORY_H
#define _GAME_MEMORY_H
#include "game_platform.h"
// 定义一个结构体表示内存池（Arena），用于分配和管理内存块
struct memory_arena {
    memory_index Size;  // 内存池的总大小
    uint8 *Base;        // 内存池的起始地址
    memory_index Used;  // 已经使用的内存大小，表示当前的偏移量
    int32 TempCount;    // 计数器，用于跟踪临时分配或操作的次数。
};

// 临时内存结构，用于管理在内存区域内的临时内存使用。
struct temporary_memory {
    memory_arena *Arena;  // 指向用于临时分配的内存区域的指针。
    memory_index Used;    // 已经使用的内存索引或已使用的内存量。
};

// 开始临时内存分配，返回一个临时内存结构。
// 用于在指定的内存区域中进行临时内存操作。
inline temporary_memory BeginTemporaryMemory(memory_arena *Arena) {
    temporary_memory Result;
    Result.Arena = Arena;       // 保存内存区域指针。
    Result.Used = Arena->Used;  // 记录当前内存区域已使用的内存量。
    ++Arena->TempCount;         // 增加临时内存操作计数。
    return Result;              // 返回临时内存结构。
}

// 结束临时内存分配，恢复内存区域的状态。
// 恢复在临时内存操作前的已使用内存量。
inline void EndTemporaryMemory(temporary_memory TempMem) {
    memory_arena *Arena = TempMem.Arena;  // 获取内存区域指针。
    Assert(Arena->Used >= TempMem.Used);  // 确保内存使用量没有减少。
    Arena->Used = TempMem.Used;           // 恢复到临时操作前的内存使用量。
    Assert(Arena->TempCount > 0);         // 确保临时内存操作计数有效。
    Arena->TempCount--;                   // 减少临时内存操作计数。
}

// 初始化内存分配池（内存区域）
internal void InitializeArena(memory_arena *Arena, memory_index Size, void *Base) {
    // 设置内存池的总大小
    Arena->Size = Size;

    // 设置内存池的起始地址
    Arena->Base = (uint8 *)Base;

    // 初始化已使用内存大小为 0
    Arena->Used = 0;
    Arena->TempCount = 0;
}
inline void Clear(memory_arena *Arena) {  //
    InitializeArena(Arena, Arena->Size, Arena->Base);
}

// 检查内存区域是否没有未完成的临时内存操作。
// 用于确保所有临时内存操作已结束，避免内存泄漏。
inline void CheckArena(memory_arena *Arena) {
    Assert(Arena->TempCount == 0);  // 确保临时内存操作计数为0。
}

struct task_with_memory {
    bool32 BeingUsed;
    bool32 DependsOnGameMode;
    memory_arena Arena;
    temporary_memory MemoryFlush;
};

struct arena_push_params {
    uint32 Flags;
    uint32 Alignment;
};
enum arena_push_flag {
    ArenaFlag_ClearToZero = 0x1,
};

inline arena_push_params DefaultArenaParams(void) {
    arena_push_params Params;
    Params.Flags = ArenaFlag_ClearToZero;
    Params.Alignment = 4;
    return Params;
}
inline memory_index GetAlignmentOffset(memory_arena *Arena,
                                       arena_push_params Params = DefaultArenaParams()) {
    memory_index ResultPoint = (memory_index)Arena->Base + Arena->Used;
    memory_index AlignmentOffset = 0;
    memory_index AlignmentMask = Params.Alignment - 1;
    if (ResultPoint & AlignmentMask) {
        AlignmentOffset = Params.Alignment - (ResultPoint & AlignmentMask);
    }
    return AlignmentOffset;
}
inline memory_index GetEffectiveSizeFor(memory_arena *Arena, memory_index SizeInit,
                                        arena_push_params Params) {
    memory_index Size = SizeInit;
    memory_index AlignmentOffset = GetAlignmentOffset(Arena, Params);
    Size += AlignmentOffset;
    return Size;
}

// 宏，用于在内存池中分配一个指定类型的对象
// 输入：Arena（内存池指针）、Type（要分配的类型）
// 输出：分配的对象指针（类型为 Type*）
#define PushStruct(Arena, Type, ...) (Type *)PushSize_(Arena, sizeof(Type), ##__VA_ARGS__)

// 宏，用于在内存池中分配一个指定类型的对象数组
// 输入：Arena（内存池指针）、Count（数组元素数量）、Type（数组元素类型）
// 输出：分配的数组指针（类型为 Type*）
#define PushArray(Arena, Count, Type, ...) \
    (Type *)PushSize_(Arena, (Count) * sizeof(Type), ##__VA_ARGS__)

#define PushSize(Arena, Size, ...) PushSize_(Arena, Size, ##__VA_ARGS__)
#define PushCopy(Arena, Size, Source, ...) Copy(Size, Source, PushSize(Arena, Size))

// 在内存池中分配指定大小的内存块
// 输入：Arena（内存池指针）、Size（要分配的内存大小）
// 输出：分配的内存块地址（void* 类型）
void *PushSize_(memory_arena *Arena, memory_index Size,
                arena_push_params Params = DefaultArenaParams());

#define ZeroStruct(Instance) ZeroSize(sizeof(Instance), &(Instance))
#define ZeroArray(Instance, Pointer) ZeroSize(Count * sizeof(Pointer[0]), Pointer);
inline void ZeroSize(memory_index Size, void *Ptr) {
    // TODO: 检查这个部分的性能
    uint8 *Byte = (uint8 *)Ptr;
    while (Size--) {
        *Byte++ = 0;
    }
}

// 在内存池中分配指定大小的内存块
// 输入：Arena（内存池指针）、Size（要分配的内存大小）
// 输出：分配的内存块地址（void* 类型）
inline void *PushSize_(memory_arena *Arena, memory_index SizeInit, arena_push_params Params) {
    memory_index Size = GetEffectiveSizeFor(Arena, SizeInit, Params);
    memory_index AlignmentOffset = GetAlignmentOffset(Arena, Params);

    Assert((Arena->Used + Size) <= Arena->Size);

    // 计算新分配的内存块的起始地址
    void *Result = Arena->Used + Arena->Base + AlignmentOffset;
    Arena->Used += Size;

    Assert(Size >= SizeInit);
    if (Params.Flags & ArenaFlag_ClearToZero) {
        ZeroSize(SizeInit, Result);
    }
    // 返回新分配的内存块的地址
    return Result;
}

inline void SubArena(memory_arena *Result, memory_arena *Arena, memory_index Size,
                     arena_push_params Params = DefaultArenaParams()) {
    Result->Size = Size;
    Result->Base = (uint8 *)PushSize(Arena, Size, Params);
    Result->TempCount = 0;
    Result->Used = 0;
}

#endif